/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frhash2.c                                          */
/*  NOTE      =                                                    */
/*  DATE      = 2014/11/12 by yaohl                                */
/*******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "frcomm.h"
#include "frlog.h"
#include "frmem.h"
#include "frstr.h"
#include "frhash2.h"

#ifdef FR_MURMURHASH
#include "murmurhash.h"
#endif

/*******************************************************************************
*  FUNC     :  生成哈希key
*  ARGS     :  p_data    (生成hash key的数据)
            :  ui_len    (生成hash key数据长度)
*  RTN      :  hash key
*  NOTE     :  DJBHash
*******************************************************************************/
unsigned long frhash_key(unsigned char *p_data, unsigned int ui_len)
{
#ifndef FR_MURMURHASH
    unsigned long ul_hash_key = 5381;
    unsigned int ui_loop;

    if(p_data == NULL || ui_len <=0)
        return 0;

    for(ui_loop = 0; ui_loop < ui_len; ui_loop++)
    {
        ul_hash_key = ((ul_hash_key << 5) + ul_hash_key) + p_data[ui_loop];
    }
    return ul_hash_key;
#else
    if(p_data == NULL || ui_len <=0)
        return 0;

    return murmurhash(p_data, ui_len, 0);
#endif
}

/*******************************************************************************
*  FUNC     :  生成指定hash表
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  ul_hash_size (hash 数组的大小)
*  RTN      :  FR_SUCC :成功, FR_FAIL :失败
*  NOTE     :
*******************************************************************************/
int frhash2_create(Frhash_header *p_hash_hdr, unsigned long ul_hash_size)
{
    int i_ret = FR_FAIL;
    unsigned long ul_loop=0L;

    if(p_hash_hdr == NULL || ul_hash_size <=0)
        return i_ret;

    p_hash_hdr->ul_hash_size = ul_hash_size;
    p_hash_hdr->p_list_array =  frmalloc( (ul_hash_size*sizeof(Frlist_header)) );

    if(!p_hash_hdr->p_list_array)
    {
        p_hash_hdr->ul_hash_size = 0L;
        FRLOG_ERROR_DETAIL("frmalloc err");
        return i_ret;
    }

    for(ul_loop=0; ul_loop < ul_hash_size; ul_loop++)
    {
        frlist_header_init(&(p_hash_hdr->p_list_array[ul_loop]) );
    }

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  生成指定hash表
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  ul_hash_size (hash 数组的大小)
*  RTN      :  成功时返回hash表头, 否则返回NULL
*  NOTE     :  使用frhash_free2释放
*******************************************************************************/
Frhash_header *frhash2_create2(unsigned long ul_hash_size)
{
    Frhash_header *p_hash_hdr=NULL;
    int i_ret_fun;

    p_hash_hdr = frmalloc(sizeof(Frhash_header));
    if(p_hash_hdr==NULL)
        return NULL;

    i_ret_fun = frhash2_create(p_hash_hdr, ul_hash_size);
    if(i_ret_fun == FR_FAIL)
    {
        frfree(p_hash_hdr);
        p_hash_hdr = NULL;
    }
    return p_hash_hdr;
}

/*******************************************************************************
*  FUNC     :  释放指定hash表
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  pf_free      (释放资源用函数指针)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frhash2_free(Frhash_header *p_hash_hdr, list_node_free pf_free)
{
    Frlist_header *p_st_list_hdr=NULL;
    unsigned long ul_loop=0L;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL || p_hash_hdr->ul_hash_size <=0 || pf_free == NULL)
        return;

    for(ul_loop=0; ul_loop < p_hash_hdr->ul_hash_size; ul_loop++)
    {
        p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_loop]);
        frlist_remove_all(p_st_list_hdr, pf_free);
    }

    frfree(p_hash_hdr->p_list_array);
    p_hash_hdr->p_list_array = NULL;

    return;
}

/*******************************************************************************
*  FUNC     :  释放指定hash表
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  pf_free      (释放资源用函数指针)
*  RTN      :
*  NOTE     : 使用frhash_create2生成hash头时,需要用该函数释放
*******************************************************************************/
void frhash2_free2(Frhash_header *p_hash_hdr, list_node_free pf_free)
{
    if(p_hash_hdr == NULL)
        return;

    frhash2_free(p_hash_hdr, pf_free);
    frfree(p_hash_hdr);

    return;
}

/*******************************************************************************
*  FUNC     :  向指定hash表里增加数据
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  ul_key       (key)
*           :  ui_key_len   (key 长度)
*           :  p_st_node_add(hash 里增加的节点)
*  RTN      :  FR_SUCC:成功，FR_FAIL：失败
*  NOTE     : p_st_node需要外部生成
*******************************************************************************/
int frhash2_addStr(Frhash_header *p_hash_hdr, char *p_key, unsigned int ui_key_len, Frlist_node *p_st_node_add)
{
    Frlist_header *p_st_list_hdr=NULL;
    unsigned long ul_hash_idx;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL
        || p_key == NULL || ui_key_len <= 0 || p_st_node_add == NULL)
        return FR_FAIL;

    //hash相关的数据设置
    ul_hash_idx = frhash_key((unsigned char *)p_key, ui_key_len) % p_hash_hdr->ul_hash_size;
    p_st_node_add->ul_idx = ul_hash_idx;
    p_st_node_add->l_key = 0L;
    p_st_node_add->p_key = frmalloc(ui_key_len+1);
    if(p_st_node_add->p_key == NULL)
    {
        p_st_node_add->ul_idx = 0L;
        p_st_node_add->l_key = 0L;
        return FR_FAIL;
    }

    memcpy(p_st_node_add->p_key, p_key, ui_key_len);
    p_st_node_add->p_key[ui_key_len] = '\0';
    p_st_node_add->ui_key_len = ui_key_len;

    p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_hash_idx]);
    frlist_push(p_st_list_hdr, p_st_node_add);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  向指定hash表里增加数据
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  l_key       (key)
*           :  p_st_node_add(hash 里增加的节点)
*  RTN      :  FR_SUCC:成功，FR_FAIL：失败
*  NOTE     : p_st_node需要外部生成
*******************************************************************************/
int frhash2_addLong(Frhash_header *p_hash_hdr, long l_key, Frlist_node *p_st_node_add)
{
    Frlist_header *p_st_list_hdr=NULL;
    unsigned long ul_hash_idx;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL || p_st_node_add == NULL)
        return FR_FAIL;

    //hash相关的数据设置
    ul_hash_idx = frhash_key((unsigned char *)&l_key, sizeof(l_key)) % p_hash_hdr->ul_hash_size;
    p_st_node_add->ul_idx = ul_hash_idx;
    p_st_node_add->l_key = l_key;
    p_st_node_add->p_key = NULL;
    p_st_node_add->ui_key_len = 0;

    p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_hash_idx]);
    frlist_push(p_st_list_hdr, p_st_node_add);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  hash表里查询指定节点
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  p_key        (key)
*           :  ui_key_len   (key 长度)
*  RTN      :  成功返回Frlist_node *,否则返回NULL
*  NOTE     :
*******************************************************************************/
Frlist_node *frhash2_getStr(Frhash_header *p_hash_hdr, char *p_key, unsigned int ui_key_len)
{
    Frlist_header *p_st_list_hdr=NULL;
    Frlist_node *p_st_node=NULL;
    unsigned long ul_hash_idx;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL || p_key==NULL || ui_key_len <= 0)
        return NULL;

    ul_hash_idx = frhash_key((unsigned char *)p_key, ui_key_len) % p_hash_hdr->ul_hash_size;
    p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_hash_idx]);

    p_st_node = FRLIST_FIRST_NODE(p_st_list_hdr);
    while(p_st_node)
    {
        if(p_st_node->ui_key_len == ui_key_len
           && p_st_node->p_key != NULL
           && memcmp(p_st_node->p_key, p_key, ui_key_len) == 0 )
            return p_st_node;
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }

    return NULL;
}

/*******************************************************************************
*  FUNC     :  hash表里查询指定节点
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  l_key        (key)
*  RTN      :  成功返回Frlist_node *,否则返回NULL
*  NOTE     :
*******************************************************************************/
Frlist_node *frhash2_getLong(Frhash_header *p_hash_hdr, long l_key)
{
    Frlist_header *p_st_list_hdr=NULL;
    Frlist_node *p_st_node=NULL;
    unsigned long ul_hash_idx;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL)
        return NULL;

    ul_hash_idx = frhash_key((unsigned char *)&l_key, sizeof(l_key)) % p_hash_hdr->ul_hash_size;
    p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_hash_idx]);

    p_st_node = FRLIST_FIRST_NODE(p_st_list_hdr);
    while(p_st_node)
    {
        if(p_st_node->l_key == l_key)
            return p_st_node;
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }

    return NULL;
}

/*******************************************************************************
*  FUNC     :  hash表里查询指定节点
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  p_data       (比较用数据)
*           :  pf_find      (比较用函数指针)
*  RTN      :  成功返回Frlist_node *,否则返回NULL
*  NOTE     :  对整个hash表进行查询，需要注意性能问题
*******************************************************************************/
Frlist_node *frhash2_find(Frhash_header *p_hash_hdr, void *p_data, list_node_find pf_find)
{
    Frlist_header *p_st_list_hdr=NULL;
    Frlist_node *p_st_node=NULL;
    unsigned long ul_hash_idx;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL
       || p_data==NULL || pf_find==NULL)
        return NULL;

    for(ul_hash_idx=0; ul_hash_idx < p_hash_hdr->ul_hash_size; ul_hash_idx++)
    {
        p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_hash_idx]);
        p_st_node = frlist_find(p_st_list_hdr, p_data, pf_find);
        if(p_st_node)
            break;
    }

    return p_st_node;
}

/*******************************************************************************
*  FUNC     :  hash表里查询指定节点
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  p_key        (key)
*           :  ui_key_len   (key 长度)
*           :  p_data       (比较用数据)
*           :  pf_find      (比较用函数指针)
*  RTN      :  成功返回Frlist_node *,否则返回NULL
*  NOTE     :  对整个hash表进行查询，需要注意性能问题
*******************************************************************************/
Frlist_node *frhash2_find_strKey(Frhash_header *p_hash_hdr, char *p_key, unsigned int ui_key_len
                               , void *p_data, list_node_find pf_find)
{
    Frlist_header *p_st_list_hdr=NULL;
    Frlist_node *p_st_node=NULL;
    unsigned long ul_hash_idx;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL
       || p_key==NULL || ui_key_len <= 0
       || pf_find==NULL)
        return NULL;

    ul_hash_idx = frhash_key((unsigned char *)p_key, ui_key_len) % p_hash_hdr->ul_hash_size;
    p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_hash_idx]);

    p_st_node = frlist_find(p_st_list_hdr, p_data, pf_find);
    return p_st_node;
}

/*******************************************************************************
*  FUNC     :  hash表里释放指定节点
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  ul_key       (key)
*           :  ui_key_len   (key 长度)
*           :  pf_free      (释放资源用函数指针)
*  RTN      :  FR_SUCC :成功, FR_FAIL :失败
*  NOTE     :
*******************************************************************************/
int frhash2_delStr(Frhash_header *p_hash_hdr, char *p_key, unsigned int ui_key_len, list_node_free pf_free)
{
    Frlist_header *p_st_list_hdr=NULL;
    Frlist_node *p_st_node=NULL;
    unsigned long ul_hash_idx;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL || p_key==NULL || ui_key_len <= 0 )
        return FR_FAIL;

    ul_hash_idx = frhash_key((unsigned char *)p_key, ui_key_len) % p_hash_hdr->ul_hash_size;
    p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_hash_idx]);

    p_st_node = FRLIST_FIRST_NODE(p_st_list_hdr);
    while(p_st_node)
    {
        if(p_st_node->ui_key_len == ui_key_len
           && p_st_node->p_key != NULL
           && memcmp(p_st_node->p_key, p_key, ui_key_len) == 0 )
        {
            frlist_node_free(p_st_list_hdr, p_st_node, 1, pf_free);
            return FR_SUCC;
        }
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }

    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  hash表里释放指定节点
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  ul_key       (key)
*           :  ui_key_len   (key 长度)
*           :  pf_free      (释放资源用函数指针)
*  RTN      :  FR_SUCC :成功, FR_FAIL :失败
*  NOTE     :
*******************************************************************************/
int frhash2_delLong(Frhash_header *p_hash_hdr, long l_key, list_node_free pf_free)
{
    Frlist_header *p_st_list_hdr=NULL;
    Frlist_node *p_st_node=NULL;
    unsigned long ul_hash_idx;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL)
        return FR_FAIL;

    ul_hash_idx = frhash_key((unsigned char *)&l_key, sizeof(l_key)) % p_hash_hdr->ul_hash_size;
    p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_hash_idx]);

    p_st_node = FRLIST_FIRST_NODE(p_st_list_hdr);
    while(p_st_node)
    {
        if(p_st_node->l_key == l_key)
        {
            frlist_node_free(p_st_list_hdr, p_st_node, 1, pf_free);
            return FR_SUCC;
        }
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }

    return FR_FAIL;
}


/*******************************************************************************
*  FUNC     :  hash表里释放指定节点
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  p_st_node_del(需要删除的节点)
*           :  pf_free      (释放资源用函数指针)
*  RTN      :  FR_SUCC :成功, FR_FAIL :失败
*  NOTE     :
*******************************************************************************/
int frhash2_del(Frhash_header *p_hash_hdr, Frlist_node *p_st_node_del, list_node_free pf_free)
{
    Frlist_header *p_st_list_hdr=NULL;
    unsigned long ul_hash_idx;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL || p_st_node_del == NULL || pf_free == NULL)
        return FR_FAIL;

    ul_hash_idx = p_st_node_del->ul_idx;
    p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_hash_idx]);

    frlist_node_free(p_st_list_hdr, p_st_node_del, 1, pf_free);
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  hash表内容出力
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  p_outbuff    (出力数据用空间)
*           :  ui_buff_size (出力数据用空间大小)
*           :  pf_show      (出力节点用函数指针)
*  RTN      :
*  NOTE     :  内容输出到p_outbuff的空间，有长度限制。(有内容截断的情况)
*******************************************************************************/
void frhash2_show(Frhash_header *p_hash_hdr, char *p_outbuff, unsigned int ui_buff_size, list_node_show pf_show)
{
    Frlist_header *p_st_list_hdr=NULL;
    unsigned int ui_used=0;
    unsigned long ul_loop=0L;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL
       || p_outbuff == NULL || ui_buff_size <= 1
       || pf_show == NULL)
        return;

    *p_outbuff = '\0';
    for(ul_loop=0; ul_loop < p_hash_hdr->ul_hash_size && ui_used <=  ui_buff_size -1; ul_loop++)
    {
        p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_loop]);
        if( frlist_empty(p_st_list_hdr) == FR_YES )
            continue;

        frlist_show(p_st_list_hdr, p_outbuff+ui_used, ui_buff_size - ui_used, pf_show);
        ui_used += strlen(p_outbuff+ui_used);
    }

    return;
}

/*******************************************************************************
*  FUNC     :  hash表内容出力
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  pp_outbuff   (出力数据用空间)
*           :  pf_show      (出力节点用函数指针)
*  RTN      :
*  NOTE     :  pp_outbuff内存空间在该函数内部生成,需要在外部释放
*******************************************************************************/
void frhash2_show_all(Frhash_header *p_hash_hdr, char **pp_outbuff, list_node_show_all pf_show)
{
    Frlist_header *p_st_list_hdr=NULL;
    Frstr *p_st_str=NULL;
    char *p_outbuff_one=NULL;
    unsigned long ul_loop=0L;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL
       || pp_outbuff == NULL
       || pf_show == NULL)
        return;

    p_st_str = frstr_new(1024);
    if(p_st_str==NULL)
    {
        frdbg("frstr_new err\n");
        return;
    }

    for(ul_loop=0; ul_loop < p_hash_hdr->ul_hash_size; ul_loop++)
    {
        p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_loop]);
        if( frlist_empty(p_st_list_hdr) == FR_YES )
            continue;

        p_outbuff_one = NULL;
        frlist_show_all(p_st_list_hdr, &p_outbuff_one, pf_show);
        if(p_outbuff_one == NULL)
            continue;

        frstr_append(p_st_str, p_outbuff_one, strlen(p_outbuff_one));
        frfree(p_outbuff_one);
    }
    *pp_outbuff = frstr_free2(&p_st_str);
    return;
}

/*******************************************************************************
*  FUNC     :  hash表内容出力 每个节点的长度分配为最大2048，超过2048请使用frhash2_show_all
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  pp_outbuff   (出力数据用空间)
*           :  pf_show      (出力节点用函数指针)
*  RTN      :
*  NOTE     :  pp_outbuff内存空间在该函数内部生成,需要在外部释放
*******************************************************************************/
void frhash2_show_all2(Frhash_header *p_hash_hdr, char **pp_outbuff, list_node_show pf_show)
{
    Frlist_header *p_st_list_hdr=NULL;
    Frstr *p_st_str=NULL;
    char *p_outbuff_one=NULL;
    unsigned long ul_loop=0L;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL
       || pp_outbuff == NULL
       || pf_show == NULL)
        return;

    p_st_str = frstr_new(1024);
    if(p_st_str==NULL)
    {
        frdbg("frstr_new err\n");
        return;
    }

    for(ul_loop=0; ul_loop < p_hash_hdr->ul_hash_size; ul_loop++)
    {
        p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_loop]);
        if( frlist_empty(p_st_list_hdr) == FR_YES )
            continue;

        p_outbuff_one = NULL;
        frlist_show_all2(p_st_list_hdr, &p_outbuff_one, pf_show);
        if(p_outbuff_one == NULL)
            continue;

        frstr_append(p_st_str, p_outbuff_one, strlen(p_outbuff_one));
        frfree(p_outbuff_one);
    }
    *pp_outbuff = frstr_free2(&p_st_str);
    return;
}

/*******************************************************************************
*  FUNC     :  对hash表内容里运行所有函数指针
*  ARGS     :  p_hash_hdr   (*Frhash_header)
*           :  p_data       (函数指针用数据，如果没有设置为NULL)
*           :  pf_run       (运行用函数指针)
*  RTN      :  0:pf_run控制退出; 1:运行到最后
*  NOTE     :
*******************************************************************************/
void frhash2_run(Frhash_header *p_hash_hdr, void *p_data, list_node_run pf_run)
{
    Frlist_header *p_st_list_hdr=NULL;
    unsigned long ul_loop=0L;

    if(p_hash_hdr == NULL || p_hash_hdr->p_list_array == NULL || pf_run == NULL)
        return;

    for(ul_loop=0; ul_loop < p_hash_hdr->ul_hash_size; ul_loop++)
    {
        p_st_list_hdr = &(p_hash_hdr->p_list_array[ul_loop]);
        if( frlist_empty(p_st_list_hdr) == FR_YES )
            continue;

        if(frlist_run(p_st_list_hdr, p_data, pf_run) ==0)
            break;
    }

    return;
}
